/*------------------------------------------------------------------------------
VnConv: Vietnamese Encoding Converter Library
UniKey Project: http://unikey.sourceforge.net
Copyleft (C) 1998-2002 Pham Kim Long
Contact: longp@cslab.felk.cvut.cz

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
--------------------------------------------------------------------------------*/

#include "stdafx.h"
#include "charset.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(_WIN32)
	#include <io.h>
	#include <fcntl.h>
#endif

#include "vnconv.h"

int vnFileStreamConvert(int inCharset, int outCharset, FILE * inf, FILE *outf);

int genConvert(VnCharset & incs, VnCharset & outcs, ByteInStream & input, ByteOutStream & output)
{
	StdVnChar stdChar;
	int bytesRead, bytesWritten;

	incs.startInput();
	outcs.startOutput();

	int ret = 1;
	while (!input.eos()) {
		if (incs.nextInput(input, stdChar, bytesRead)) {
			if (stdChar != INVALID_STD_CHAR) {
				if (VnCharsetLibObj.m_options.toLower)
					stdChar = StdVnToLower(stdChar);
				else if (VnCharsetLibObj.m_options.toUpper)
					stdChar = StdVnToUpper(stdChar);
				if (VnCharsetLibObj.m_options.removeTone)
					stdChar = StdVnRemoveTone(stdChar);
				ret = outcs.putChar(output, stdChar, bytesWritten);
			}
		}
		else break;
	}
	return (ret? 0 : VNCONV_OUT_OF_MEMORY);
}

//----------------------------------------------
// Arguments:
//       inCharset: charset of input
//       outCharset: charset of output
//       input: input data
//       output: output data
//       inLen: [in]  size of input. if inLen = -1, input data is null-terminated.
//              [out] if input inLen != -1, output iLen is the numbers of byte left in input.
//       maxOutLen: [in] size of output.
//                  [out] number of bytes output, if enough memory
//                        number of bytes needed for output, if not enough memory
// Returns:  0 if successful
//           error code: if failed
//----------------------------------------------
int VnConvert(int inCharset, int outCharset, BYTE *input, BYTE *output, int & inLen, int & maxOutLen)
{
	int ret = -1;
	if (inLen != -1 && inLen < 0) // invalid inLen
		return ret;

	VnCharset *pInCharset = VnCharsetLibObj.getVnCharset(inCharset);
	VnCharset *pOutCharset = VnCharsetLibObj.getVnCharset(outCharset);

	if (!pInCharset || !pOutCharset)
		return VNCONV_INVALID_CHARSET;

	StringBIStream is(input, inLen);
	StringBOStream os(output, maxOutLen);

	ret = genConvert(*pInCharset, *pOutCharset, is, os);
	maxOutLen = os.getOutBytes();
	inLen = is.left();
	return ret;
}

//---------------------------------------
// Arguments:
//   inFile: input file name. NULL if STDIN is used
//   outFile: output file name, NULL if STDOUT is used
// Returns:
//     0: successful
//     errCode: if failed
//---------------------------------------
int VnFileConvert(int inCharset, int outCharset, const char *inFile, const char *outFile)
{
	FILE *inf = NULL;
	FILE *outf = NULL;
	int ret = 0;
	char *tmpName;

	if (inFile == NULL) {
		inf = stdin;
#if defined(_WIN32)
		_setmode( _fileno(stdin), _O_BINARY);
#endif
	}
	else {
		inf = fopen(inFile, "rb");
		if (inf == NULL) {
			ret = VNCONV_ERR_INPUT_FILE;
			goto end;
		}
	}

	if (outFile == NULL)
		outf = stdout;
	else {
		// setup temporary output file (because real output file may be the same as input file
		char outDir[256];
		strcpy(outDir, outFile);

#if defined(_WIN32)
		char *p = strrchr(outDir, '\\');
#else
		char *p = strrchr(outDir, '/');
#endif

		if (p == NULL)
			outDir[0] = 0;
		else
			*p = 0;

		tmpName = tempnam(outDir, NULL);

		if (tmpName == NULL) {
			fclose(inf);
			ret = VNCONV_ERR_OUTPUT_FILE;
			goto end;
		}
		outf = fopen(tmpName, "wb");

		if (outf == NULL) {
			fclose(inf);
			free(tmpName);
			ret = VNCONV_ERR_OUTPUT_FILE; 
			goto end;
		}
	}


	ret = vnFileStreamConvert(inCharset, outCharset, inf, outf);
	if (inf != stdin)
		fclose(inf);
	if (outf != stdout) {
		fclose(outf);

		// delete output file if exisits
		if (ret == 0) {
			remove(outFile);
#if !defined(_WIN32)
			char cmd[256];
			sprintf(cmd, "mv %s %s", tmpName, outFile);
			system(cmd);
#else
			if (rename(tmpName, outFile) != 0) {
				remove(tmpName);
				free(tmpName);
				ret = VNCONV_ERR_OUTPUT_FILE;
				goto end;
			}
#endif
		}
		else 
			remove(tmpName);
		free(tmpName);
	}

end:
#if defined(_WIN32)
	if (inf == stdin) {
		_setmode( _fileno(stdin), _O_BINARY);
	}
#endif
	return ret;
}

//------------------------------------------------
// Returns:
//     0: successful
//     errCode: if failed
//---------------------------------------
int vnFileStreamConvert(int inCharset, int outCharset, FILE * inf, FILE *outf)
{
	int ret = 0;

	VnCharset *pInCharset = VnCharsetLibObj.getVnCharset(inCharset);
	VnCharset *pOutCharset = VnCharsetLibObj.getVnCharset(outCharset);

	if (!pInCharset || !pOutCharset)
		return VNCONV_INVALID_CHARSET;

	if (outCharset == CONV_CHARSET_UNICODE) {
		WORD sign = 0xFEFF;
		fwrite(&sign, sizeof(WORD), 1, outf);
	}

	FileBIStream is;
	FileBOStream os;

	is.attach(inf);
	os.attach(outf);

	return genConvert(*pInCharset, *pOutCharset, is, os);
}
